/****************************************************************************/
/*
* xml shm api.
*/
/****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <netinet/in.h> /*for ntohl*/
#include "libmdm.h"

#include "cms_mdm.h"
#include "cms_common.h"
#include "cms_log.h"



#ifndef SYSDEF_PARSER_ON_HOST
//MUST NOT SHOW IN SYSDEF_PARSER_ON_HOST

#define SUPPORT_MAXNODENUMBER
#define TYP_INIT 0
#define TYP_SMLE 1
#define TYP_BIGE 2
static int typ = TYP_INIT;

unsigned long long HTONLL( unsigned long long src )
{
	unsigned char c;
	union {
		unsigned long long ull;
		unsigned char c[ 8 ];
	} x;

	if ( typ == TYP_INIT )
	{
		x.ull = 0x01;
		typ = (x.c[7] == 0x01ULL) ? TYP_BIGE : TYP_SMLE;
	}
	if ( typ == TYP_BIGE )
		return src;

	x.ull = src;
	c = x.c[0]; x.c[0] = x.c[7]; x.c[7] = c;
	c = x.c[1]; x.c[1] = x.c[6]; x.c[6] = c;
	c = x.c[2]; x.c[2] = x.c[5]; x.c[5] = c;
	c = x.c[3]; x.c[3] = x.c[4]; x.c[4] = c;

	return x.ull;
}

unsigned long long NTOHLL( unsigned long long src )
{
	unsigned long long rval;
	unsigned char *data = (unsigned char *)&rval;
	//unsigned char c;
	union {
		unsigned long long ull;
		unsigned char c[ 8 ];
	} x;

	if ( typ == TYP_INIT )
	{
		x.ull = 0x01;
		typ = (x.c[7] == 0x01ULL) ? TYP_BIGE : TYP_SMLE;
	}
	if ( typ == TYP_BIGE )
		return src;
	
	data[0] = src >> 56;
	data[1] = src >> 48;
	data[2] = src >> 40;
	data[3] = src >> 32;
	data[4] = src >> 24;
	data[5] = src >> 16;
	data[6] = src >> 8;
	data[7] = src >> 0;

	return rval;
}

uint64_t cmsXmlGetPreObjIA( cmsXmlCb_t *xmlShmCb,cmsoffset_t objOffset )
{
	uint64_t IAvalue = *( (uint64_t *)( ( xmlShmCb->baseaddr + objOffset ) - PREIA_LEN ) );
	return NTOHLL(IAvalue);
}

/* utility func. */
void printIAArray( uint64_t value )
{
	int i = 0;

	for ( i = 1; i < 8; i++ )
	{
		CMS_LOG(LL_FLOOD,  "%d, ", cmsXmlGetIAInfo( value, i ) );
	}
	CMS_LOG(LL_FLOOD,  "%d\n", cmsXmlGetIAInfo( value, IA_DEPTHNUM ) );
}

void printIANext( cmsXmlCb_t *xmlShmCb, cmsoffset_t offset )
{
	cmsoffset_t getOffset = 0;

	CMS_LOG(LL_FLOOD,  "offset=%d, node=%d, attr=%d, ", offset, cmsXmlGetPreObjNode( xmlShmCb, offset ), cmsXmlGetPreObjAttr( xmlShmCb, offset ) );
	printIAArray( cmsXmlGetPreObjIA( xmlShmCb, offset ) );

	getOffset = cmsXmlGetPreObjNext( xmlShmCb, offset );
	while ( getOffset )
	{
		CMS_LOG(LL_FLOOD,  "offset=%d, node=%d, attr=%d, ", getOffset, cmsXmlGetPreObjNode( xmlShmCb, getOffset ), cmsXmlGetPreObjAttr( xmlShmCb, getOffset ) );
		printIAArray( cmsXmlGetPreObjIA( xmlShmCb, getOffset ) );
		getOffset = cmsXmlGetPreObjNext( xmlShmCb, getOffset );
	}
}

void printObjList( objectList_t** objList )
{
	objectList_t *nextNode = NULL, *newNode = *objList;

	if ( *objList == NULL )
		CMS_LOG(LL_FLOOD, "objList is NULL\n" );

	while ( newNode )
	{
		nextNode = newNode->next;
		CMS_LOG(LL_FLOOD,  "objList: OID=%d, ", newNode->OID );
		printIAArray( newNode->IA );
		newNode = nextNode;
	}
}

void printUsedCallocCounter( cmsXmlCb_t *xmlShmCb, objectNode_t *node )
{
	uint32_t counter = 0, objSize = 0;

	//printf( "node->object=%lu, attr=%lu\n", node->object, node->attributes );
	if ( node->attributes & ATTR_INDEXCHILD )
	{
		if ( node->attributes & ATTR_OBJECTNODE )
		{
			objSize = node->object_size & GET_OBJECT_SIZE_MASK;
			counter = ( node->object_size & GET_CALLOC_COUNTER_MASK ) >> GET_CALLOC_COUNTER_SHIFT;
			if ( counter )
				CMS_LOG(LL_FLOOD,  "OID=%d, counter=%d, size=%d\n", cmsXml_GetOIDByOffset( xmlShmCb, node->object ), counter, objSize );
		}
		if ( node->child )
		{
			printUsedCallocCounter( xmlShmCb, (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, node->child ) );
		}
	}
	else
	{
		if ( node->attributes & ATTR_OBJECTNODE )
		{
			objSize = node->object_size & GET_OBJECT_SIZE_MASK;
			counter = ( node->object_size & GET_CALLOC_COUNTER_MASK ) >> GET_CALLOC_COUNTER_SHIFT;
			if ( counter )
				CMS_LOG(LL_FLOOD,  "OID=%d, counter=%d, size=%d\n", cmsXml_GetOIDByOffset( xmlShmCb, node->object ), counter, objSize );
		}
		if ( node->child )
		{
			printUsedCallocCounter( xmlShmCb, (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, node->child ) );
		}
		if ( node->sibling.tree.prev )
		{
			printUsedCallocCounter( xmlShmCb, (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, node->sibling.tree.prev ) );
		}
		if ( node->sibling.tree.next )
		{
			printUsedCallocCounter( xmlShmCb, (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, node->sibling.tree.next ) );
		}
	}
}

/* compare IA value with depth. 0 is different, 1 is the same. */
int compareIAByDepth( uint64_t a, uint64_t b, uint8_t depth )
{
	int i = 1;

	for ( i = 1; i <= depth; i++ )
	{
		if ( cmsXmlGetIAInfo( a, i ) != cmsXmlGetIAInfo( b, i ) )
		{
			return 0;
		}
	}
	return 1;
}

/* -1 is "a" larger, 1 is "b" larger, 0 is equal. */
int compareIAOrder( uint64_t a, uint64_t b )
{
	int i = 1;

	for ( i = 1; i <= IA_DEPTHNUM; i++ )
	{
		if ( cmsXmlGetIAInfo( a, i ) > cmsXmlGetIAInfo( b, i ) )
		{
			return -1;
		}
		if ( cmsXmlGetIAInfo( a, i ) < cmsXmlGetIAInfo( b, i ) )
		{
			return 1;
		}
	}
	return 0;
}

uint64_t cmsXmlSetIAValue( uint64_t originalValue, int index, uint64_t setValue )
{
	uint64_t testFF = 0xFF;
	return ( originalValue&(~(testFF<<((8-index)*8)))) | (setValue<<((8-index)*8) );
}

/*
**Construct new IA value : wrapper for the API "cmsXmlSetIAValue" to make setting IA more simple
**Usage: 
**newIAValue = cmsXmlConstructIAValue(4,"1,2,3,4"); or
**newIAValue = cmsXmlConstructIAValue(4,"1,2,%d,%d", i, j);
*/
uint64_t cmsXml_ConstructIAValue(const char *fileName, const char *funcName, const int lineNo, uint8_t depth, char* iValue_p, ...) 
{ 
	char *ptr = NULL;
	char *savePtr = NULL;
	int index = 1;
	int iValue = 0;
	char iValueBuffer[32] = {0};
	uint64_t newIAValue = 0;
	va_list args;

	//check if depth exceeds Max!
	if(depth > INSTANCE_DEPTH_MAX || depth <= 0){
		CMS_LOG(LL_ERROR, "Error!!! IA depth exceeds Max 1~%d !!!\n", INSTANCE_DEPTH_MAX);
		return 0;
	}
	
	//Get the first ivalue in the string.
	strcpy(iValueBuffer, iValue_p);
	ptr = strtok_r(iValueBuffer, ",", &savePtr);
	if(ptr == NULL){
		CMS_LOG(LL_ERROR, "Error!!! IA iValue is NULL [%s]!!!\n", iValue_p);		
		return 0;
	}
	
	va_start(args, iValue_p);
	//Loop for finding Ivalue from argument to generate IA value.
	while(ptr && index <= depth){
		if(strstr(ptr, "%d")){
			iValue = va_arg(args,int);
		}else{
			iValue = atoi(ptr);
		}
		//iValue should be 1~255
		if(iValue <= 0 || iValue > 0xff){
			CMS_LOG(LL_ERROR, "[%s-%s-%d]Error!!! IA iValue is not in 1~255 [%s][%d][%d]!!!\n", 
				fileName, funcName, lineNo, iValue_p,index,iValue);
			newIAValue = 0;
			goto End;
		}
		newIAValue	= cmsXmlSetIAValue( newIAValue, index, iValue);
		
		ptr = strtok_r(NULL, ",", &savePtr);
		index++;

		//Check the length of iValue_p and depth
		if(ptr != NULL && index > depth){
			CMS_LOG(LL_ERROR, "Error!!! The number of iValue is more than the depth [%s]!!!\n", iValue_p);		
			newIAValue = 0;
			goto End;
		}else if(ptr == NULL && index <= depth){
			CMS_LOG(LL_ERROR, "Error!!! The IA depth is more than number of provided iValue [%s]\n", iValue_p);		
			newIAValue = 0;
			goto End;
		}
	}
	
	//Set the IA depth
	newIAValue = cmsXmlSetIAValue(newIAValue, IA_DEPTHNUM, depth);
	
End:
	va_end(args);
	return newIAValue;
}


void cmsXml_SetPreObjIA( cmsXmlCb_t *xmlShmCb, cmsoffset_t objOffset, uint64_t valueIA )
{
	uint64_t newValue = HTONLL(valueIA);
	memcpy( ( xmlShmCb->baseaddr + objOffset ) - PREIA_LEN, &newValue, sizeof( uint64_t ) );
}

void cmsXml_SetPreObjNext( cmsXmlCb_t *xmlShmCb, cmsoffset_t objOffset, cmsoffset_t valueOffset )
{
	cmsoffset_t newValue = valueOffset;
	memcpy( ( xmlShmCb->baseaddr + objOffset ) - PRENEXT_LEN, &newValue, sizeof( cmsoffset_t ) );
}

void cmsXml_SetPreObjAttr( cmsXmlCb_t *xmlShmCb, cmsoffset_t objOffset, uint32_t valueAttr )
{
	uint32_t newValue = valueAttr;
	memcpy( ( xmlShmCb->baseaddr + objOffset ) - PREATTR_LEN, &newValue, sizeof( uint32_t ) );
}

void cmsXml_SetCBData( cmsXmlCb_t *xmlShmCb, cmsoffset_t offset )
{
	objectNode_t *tmpNode = NULL;
	
	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return;
	}
	
	if ( offset == 0 )
	{
		xmlShmCb->objectNode = NULL;
		xmlShmCb->objectSize = 0;

		xmlShmCb->OID = -1;
		xmlShmCb->IA = 0;
		xmlShmCb->offset = 0;
		return;
	}

	tmpNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, cmsXmlGetPreObjNode( xmlShmCb, offset ) );
	if ( tmpNode == NULL )
	{
		CMS_LOG(LL_ERROR, "error offset=%d\n", offset );
		xmlShmCb->objectNode = NULL;
		xmlShmCb->objectSize = 0;

		xmlShmCb->OID = -1;
		xmlShmCb->IA = 0;
		xmlShmCb->offset = 0;
		return;
	}

	xmlShmCb->objectNode = tmpNode;
	xmlShmCb->objectSize = tmpNode->object_size & GET_OBJECT_SIZE_MASK;

	xmlShmCb->OID = cmsXml_GetOIDByOffset( xmlShmCb, offset );
	xmlShmCb->IA = cmsXmlGetPreObjIA( xmlShmCb, offset );
	xmlShmCb->offset = offset;
}

void cmsXml_SetPreObjNonConfig( cmsXmlCb_t *xmlShmCb, cmsoffset_t offset )
{
	uint32_t attr = 0;

	/* TBD: if all object is inactive, parents need to set inactive? */
	attr = cmsXmlGetPreObjAttr( xmlShmCb, offset );
	attr &= ~ATTR_NODECONFIGURED;
	cmsXml_SetPreObjAttr( xmlShmCb, offset, attr );
}

/* create index object or restore object data or copy from prototype. */
cmsoffset_t cmsXml_SetObjDefault( cmsXmlCb_t *xmlShmCb, cmsoffset_t offset, int flag )
{
	objectNode_t *srcNode = NULL;
	void *srcObj = NULL, *dstObj = NULL;
	uint32_t objSize = 0;

	/* get prototype node. */
	srcNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, cmsXmlGetPreObjNode( xmlShmCb, offset ) );

	/* get prototype obj real address. */
	srcObj = cmsXmlGetObjRealAddr( xmlShmCb, srcNode->object );

	/* get object size. */
	objSize = srcNode->object_size & GET_OBJECT_SIZE_MASK;

	/* get target obj real address. */
	if ( flag == OBJECT_CREATE_OBJECT ) /* append new object to last memory space. */
	{
		if((cmsXmlGetUsedShmSize(xmlShmCb)+ objSize + PREOBJ_LEN) > X2S_MEMORY_SIZE){
			CMS_LOG(LL_ERROR, "add object will exceed than max shm size(%u), please enlarge the max shm size!!!", X2S_MEMORY_SIZE);
			return 0;
		}
		dstObj = cmsXmlGetObjRealAddr( xmlShmCb, cmsXmlGetUsedShmSize( xmlShmCb ) + PREOBJ_LEN );
		cmsXml_SetUsedShmSize( xmlShmCb, objSize + PREOBJ_LEN );
	}
	else
		dstObj = cmsXmlGetObjRealAddr( xmlShmCb, offset );

	/* copy index object from prototype to target index object. */
	if ( flag ) /* include preobj data. */
	{
		memcpy( dstObj - PREOBJ_LEN, srcObj - PREOBJ_LEN, objSize + PREOBJ_LEN );
		cmsXml_SetPreObjIA( xmlShmCb, cmsXmlGetPtrOffset( xmlShmCb, dstObj ), 0 );
		cmsXml_SetPreObjNext( xmlShmCb, cmsXmlGetPtrOffset( xmlShmCb, dstObj ), 0 );
	}
	else /* exclude preobj data. */
		memcpy( dstObj, srcObj, objSize );

	return cmsXmlGetPtrOffset( xmlShmCb, dstObj );
}

void cmsXml_SetUsedShmSize( cmsXmlCb_t *xmlShmCb, uint32_t objSize )
{
	uint32_t newSize = ( objSize + cmsXmlGetUsedShmSize( xmlShmCb ) );
	memcpy( xmlShmCb->baseaddr + sizeof( uint32_t ) * 2, &newSize, sizeof( uint32_t ) );
}

void cmsXml_SetStringShmOffset( cmsXmlCb_t *xmlShmCb, uint32_t stringSize )
{
	uint32_t newOffset = ( cmsXmlGetStringShmOffset( xmlShmCb ) - stringSize );

	if ( newOffset < cmsXmlGetUsedShmSize( xmlShmCb ) )
	{
		CMS_LOG(LL_FLOOD,  "we are out of memory = %d\n", stringSize );
	}
	else
		memcpy( xmlShmCb->baseaddr + sizeof( uint32_t ) * 3, &newOffset, sizeof( uint32_t ) );
}

/* copy from cmsXml_SetNodeStatus. change to set attribute by object offset. */
void cmsXml_SetPreObjStatus( cmsXmlCb_t *xmlShmCb, cmsoffset_t offset, int active )
{
	objectNode_t *node = NULL, *parent = NULL;
	uint32_t attr = 0;

	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return;
	}
	node = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, cmsXmlGetPreObjNode( xmlShmCb, offset ) );

	/* we should not set active/inactive on prototype object. */
	if ( node->object == offset )
		return;

	if ( active == INDEX_OBJECT_ACTIVE ) /* enable. */
	{
		/* set attribute to preobj. */
		attr = cmsXmlGetPreObjAttr( xmlShmCb, offset );
		attr |= ATTR_NODECONFIGURED;
		cmsXml_SetPreObjAttr( xmlShmCb, offset, attr );

		/* set attribute to parents. */
		parent = node;
		while ( parent )
		{
			parent->attributes |= ATTR_NODECONFIGURED;
			parent = cmsXmlGetObjRealAddr( xmlShmCb, parent->parent );
		}
	}
	else if ( active == INDEX_OBJECT_INACTIVE ) /* disable. */
	{
		cmsXml_DelObjectByOffset( xmlShmCb, offset );
	}
}

/* sort newOffset to ordered list. */
void cmsXml_SortNewObject( cmsXmlCb_t *xmlShmCb, cmsoffset_t srcOffset, cmsoffset_t newOffset )
{
	cmsoffset_t getOffset = 0, preNewOffset = 0, preOffset = srcOffset;

	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return;
	}
	getOffset = cmsXmlGetPreObjNext( xmlShmCb, srcOffset );
	/* find offset which NEXT is newOffset. */
	while ( getOffset )
	{
		if ( cmsXmlGetPreObjNext( xmlShmCb, getOffset ) == newOffset )
		{
			preNewOffset = getOffset;
			break;
		}
		getOffset = cmsXmlGetPreObjNext( xmlShmCb, getOffset );
	}

	/* find position to insert newOffset. */
	getOffset = cmsXmlGetPreObjNext( xmlShmCb, srcOffset );
	while ( getOffset && ( getOffset != newOffset ) )
	{
		if ( compareIAOrder( cmsXmlGetPreObjIA( xmlShmCb, getOffset ), cmsXmlGetPreObjIA( xmlShmCb, newOffset ) ) >= 0 ) /* if 1, newOffset IA is larger than getOffset IA. */
		{
			preOffset = getOffset;
			getOffset = cmsXmlGetPreObjNext( xmlShmCb, getOffset );
		}
		else /* insert newOffset before getOffset. */
		{
			cmsXml_SetPreObjNext( xmlShmCb, preNewOffset, cmsXmlGetPreObjNext( xmlShmCb, newOffset ) );
			cmsXml_SetPreObjNext( xmlShmCb, preOffset, newOffset );
			cmsXml_SetPreObjNext( xmlShmCb, newOffset, getOffset );
			break;
		}
	}
}


/* get OID by object offset in cmsXml_obj_id.h. */
int cmsXml_GetOIDByOffset( cmsXmlCb_t *xmlShmCb, cmsoffset_t offset )
{
	objectNode_t *tmpNode = NULL;
	int OID = cmsXml_GetOIDByTable( offset );

	if ( OID == -1 )
	{
		tmpNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, cmsXmlGetPreObjNode( xmlShmCb, offset ) );
		return cmsXml_GetOIDByTable( tmpNode->object );
	}
	else
	{
		return OID;
	}
}


/*
	Description: 
		This function is used to free memory allocate at cmsXml_getFullPathByID()
	Parameters:
		name: pointer of cmsXml_getFullPathByID()
	return:
		return CMS_OK
	needs to call this function everytime after cmsXml_getFullPathByID()
		
*/
int cmsXml_freeFullPathBuffer(void **name){

	if(*name != NULL){
		free(*name);
	}
	
	return CMS_OK;
}


/* this ptr is real addr in shm. */
void *cmsXml_CallocSpace( cmsXmlCb_t *xmlShmCb, int OID, void *ptr )
{
	void *cPtr = NULL;
	
	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return NULL;
	}
	cPtr = (void *)calloc( xmlShmCb->objectSize, 1 );
	memcpy( cPtr, ptr, xmlShmCb->objectSize );
	cmsXml_CallocCounter( xmlShmCb, OID, CALLOC_COUNTER_INCREASE );

	return cPtr;
}

int cmsXml_FreeCallocSpace( cmsXmlCb_t *xmlShmCb, int OID, void **object )
{
	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return CMS_NOK;
	}
	if ( *object != NULL )
	{
		free( *object );
		cmsXml_CallocCounter( xmlShmCb, OID, CALLOC_COUNTER_DECREASE );
		return CMS_OK;
	}
	else
	{
		return CMS_NOK;
	}
}

/* action: 0 is del; 1 is add; other is get counter. */
int cmsXml_CallocCounter( cmsXmlCb_t *xmlShmCb, int OID, int action )
{
	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return CMS_NOK;
	}
	objectNode_t *tmpNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, cmsXmlGetPreObjNode( xmlShmCb, cmsXml_GetOffsetByOID( OID ) ) );
	uint32_t counter = 0, objSize = 0;
	int tmpOID = OID;
	
	if ( tmpNode == NULL )
	{
		CMS_LOG( LL_ERROR, "no this object\n" );
		return CMS_NOK;
	}
	if ( tmpNode->attributes & ATTR_INDEXNODE ) /* get the indexchild OID. */
	{
		tmpNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, tmpNode->child );
		tmpOID = cmsXml_GetOIDByOffset( xmlShmCb, tmpNode->object );
	}

	objSize = tmpNode->object_size & GET_OBJECT_SIZE_MASK;
	counter = ( tmpNode->object_size & GET_CALLOC_COUNTER_MASK ) >> GET_CALLOC_COUNTER_SHIFT;
	//CMS_LOG(LL_FLOOD, "OID=%d, objSize=%lu, counter=%lu, action=%d\n", tmpOID, objSize, counter, action );

	if ( action == CALLOC_COUNTER_DECREASE ) /* decrease 1 in counter. */
	{
		if ( counter )
		{
			counter--;
			tmpNode->object_size = objSize + ( counter << GET_CALLOC_COUNTER_SHIFT );
		}
		else
		{
			CMS_LOG(LL_ERROR, "OID=%d, tmpOID %d, counter is 0\n", OID, tmpOID );
			return CMS_NOK;
		}
	}
	else if ( action == CALLOC_COUNTER_INCREASE ) /* increase 1 in counter. */
	{
		counter++;
		tmpNode->object_size = objSize + ( counter << GET_CALLOC_COUNTER_SHIFT );
	}
	else if ( action == CALLOC_COUNTER_DISPLAY ) /* get counter. */
	{
		return (int)counter;
	}

	return CMS_OK;
}

/*
	description: 
		get object by OID and IA, and then fill corresponded info in xmlShmCb.
	parameters:
		xmlShmCb: xml shm control block.
		OID: object ID, please refer to cmsXml_obj_id.h.
		IA: instance array.
		flag: NULL_IF_NOT_EXISTED, ADD_IF_NOT_EXISTED, CALLOC_IF_EXISTED.
	return:
		the real object address or NULL.
		xmlShmCb->OID, xmlShmCb->IA, xmlShmCb->offset.
	called by:
	example:
		{}
*/
void *cmsXml_GetObjectByOID( cmsXmlCb_t *xmlShmCb, int OID, uint64_t objIA, int flag )
{
	void *ptr = NULL;
	
	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlShmCb is NULL!!!\n");
		return NULL;
	}
	
	if((xmlShmCb->readOnly == 1) && (flag != NULL_IF_NOT_EXISTED)){
		CMS_LOG(LL_ERROR, "current app authority of xml share memory is read only, can't use ADD_IF_NOT_EXITED, please use right API & right FLAG!!!\n");
		return NULL;
	}
	
	XML_LOCK(&xmlShmCb->cmsMutex->lock);
	ptr = cmsXml_objHandleByOID( xmlShmCb, OID, objIA, flag );
	XML_UNLOCK(&xmlShmCb->cmsMutex->lock);

	return ptr;
}

void *cmsXml_objHandleByOID( cmsXmlCb_t *xmlShmCb, int OID, uint64_t objIA, int flag )
{
	objectNode_t *tmpNode = NULL;
	uint64_t getIAValue = 0;
	cmsoffset_t getOffset = 0, srcOffset = cmsXml_GetOffsetByOID( OID );
	void *ptr = NULL;

	/*
		case 1: if this OID is indexnode, create it or not by flag.
		case 2: if the depth of objIA is the same with OID's,
			2.1: if objIA is 0, it is normal object, just return real addr by OID table.
			2.2: if IA has value, it is index object. compare IA value to get object and return real addr.
		case 3: if the depth of objIA is different with OID's,
			3.1: if objIA is 0, return real addr of prototype object.
			3.2: if objIA is not 0, return NULL.
	*/
	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return NULL;
	}
	tmpNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, cmsXmlGetPreObjNode( xmlShmCb, srcOffset ) );
	if ( tmpNode == NULL )
	{
		CMS_LOG( LL_FLOOD, "no this OID=%d.\n", OID );
		return NULL;
	}

	/*when compute objIA error, and child index, retun null pointer*/
	/*if ((tmpNode->attributes & ATTR_INDEXCHILD)  && (objIA == 0)){
		CMS_LOG(LL_INFO, "index child id %d, objIA is 0\n", OID);
		return NULL;
	}*/

	if ( tmpNode->attributes & ATTR_INDEXNODE ) /* case 1 */
	{
		if ( flag & ADD_IF_NOT_EXISTED )
		{
			ptr = cmsXml_AddIndexChildObject( xmlShmCb, OID, objIA );

			if ( ptr == NULL )
			{
				cmsXml_SetCBData( xmlShmCb, 0 );
				return NULL;
			}
			else
			{
				if ( flag & CALLOC_IF_EXISTED )
				{
					return cmsXml_CallocSpace( xmlShmCb, OID, ptr );
				}
				else
				{
					return ptr;
				}
			}
		}
		else
		{
			cmsXml_SetCBData( xmlShmCb, 0 );
			return NULL;
		}
	}
	else if ( cmsXmlGetIADepth( objIA ) == cmsXmlGetIADepth( cmsXmlGetPreObjIA( xmlShmCb, srcOffset ) ) )
	{
		if ( cmsXmlGetIADepth( objIA ) == 0 ) /* case 2.1 */
		{
			ptr = cmsXml_getObjectByID( xmlShmCb, srcOffset );

			if ( ptr == NULL )
			{
				cmsXml_SetCBData( xmlShmCb, 0 );
				return NULL;
			}
			else
			{
				cmsXml_SetCBData( xmlShmCb, cmsXmlGetPtrOffset( xmlShmCb, ptr ) );
				if ( flag == CALLOC_IF_EXISTED )
				{
					return cmsXml_CallocSpace( xmlShmCb, OID, ptr );
				}
				else
				{
					return ptr;
				}
			}
		}
		else /* case 2.2 */
		{
#ifdef SUPPORT_MAXNODENUMBER /* support add smaller index number. */
			if ( tmpNode->attributes & ATTR_INDEXCHILD )
			{
				if ( cmsXmlGetIAInfo( objIA, cmsXmlGetIADepth( objIA ) ) > tmpNode->sibling.child_count )
				{
					cmsXml_SetCBData( xmlShmCb, 0 );
					return NULL;
				}
			}
			while ( !( tmpNode->attributes & ATTR_INDEXCHILD ) )
			{
				tmpNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, tmpNode->parent );
				if ( tmpNode->attributes & ATTR_INDEXCHILD )
				{
					if ( cmsXmlGetIAInfo( objIA, cmsXmlGetIADepth( objIA ) ) > tmpNode->sibling.child_count )
					{
						cmsXml_SetCBData( xmlShmCb, 0 );
						return NULL;
					}
					break;
				}
			}
#endif
			getOffset = cmsXmlGetPreObjNext( xmlShmCb, srcOffset );
			while( getOffset )
			{
				getIAValue = cmsXmlGetPreObjIA( xmlShmCb, getOffset );
				if ( compareIAByDepth( objIA, getIAValue, cmsXmlGetIADepth( objIA ) ) ) /* find! */
				{
					if ( ( cmsXmlGetPreObjAttr( xmlShmCb, getOffset ) ) & ATTR_NODECONFIGURED ) /* this index object is active, just return real addr. */
					{
						cmsXml_SetCBData( xmlShmCb, getOffset );
						ptr = cmsXmlGetObjRealAddr( xmlShmCb, getOffset );
						if ( flag & CALLOC_IF_EXISTED )
						{
							return cmsXml_CallocSpace( xmlShmCb, OID, ptr );
						}
						else
						{
							return ptr;
						}
					}
					else /* this index object is inactive, check flag for add or return NULL. */
					{
						if ( flag & ADD_IF_NOT_EXISTED ) /* add this index object. */
						{
							ptr = cmsXml_AddObjectWithAssignIA( xmlShmCb, OID, objIA );

							if ( ptr == NULL )
							{
								cmsXml_SetCBData( xmlShmCb, 0 );
								return NULL;
							}
							else
							{
								if ( flag & CALLOC_IF_EXISTED )
								{
									return cmsXml_CallocSpace( xmlShmCb, OID, ptr );
								}
								else
								{
									return ptr;
								}
							}
						}
						else /* do not add, return NULL. */
						{
							cmsXml_SetCBData( xmlShmCb, 0 );
							return NULL;
						}
					}
				}
				else /* not find, continue to get NEXT. */
				{
					getOffset = cmsXmlGetPreObjNext( xmlShmCb, getOffset );
				}
			}

			/* not find with IA, add or return NULL. */
			if ( flag & ADD_IF_NOT_EXISTED ) /* add this index object. */
			{
				ptr = cmsXml_AddObjectWithAssignIA( xmlShmCb, OID, objIA );

				if ( ptr == NULL )
				{
					cmsXml_SetCBData( xmlShmCb, 0 );
					return NULL;
				}
				else
				{
					if ( flag & CALLOC_IF_EXISTED )
					{
						return cmsXml_CallocSpace( xmlShmCb, OID, ptr );
					}
					else
					{
						return ptr;
					}
				}
			}
			else
			{
				cmsXml_SetCBData( xmlShmCb, 0 );
				return NULL;
			}
		}
	}
	else
	{
		if ( objIA ) /* case 3.2: depth is different from prototype IA. */
		{
			cmsXml_SetCBData( xmlShmCb, 0 );
			return NULL;
		}
		else /* case 3.1: if IA is 0, return real addr of prototype object. */
		{
			cmsXml_SetCBData( xmlShmCb, srcOffset );
			return cmsXmlGetObjRealAddr( xmlShmCb, srcOffset );
		}
	}

	return NULL; /* something wrong! */
}

/*
	description: 
		get object by name and fill corresponded info in xmlShmCb.
	parameters:
		xmlShmCb: xml shm control block.
		name: full object path name.
		flag: NULL_IF_NOT_EXISTED, ADD_IF_NOT_EXISTED, CALLOC_IF_EXISTED.
	return:
		the real object address or NULL.
		xmlShmCb->OID, xmlShmCb->IA, xmlShmCb->offset.
	called by:
	example:
		{}
*/
void *cmsXml_GetObjectByName( cmsXmlCb_t *xmlShmCb, char *name, int flag )
{
	void *ptr = NULL;

	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlShmCb is NULL\n" );
		return NULL;
	}

	if(name == NULL || strlen(name) < strlen("InternetGatewayDevice")){
		CMS_LOG(LL_ERROR, "object name is NULL or length(%lu) is short\n", name == NULL ? 0 : strlen(name));
		return NULL;
	}
	
	if((xmlShmCb->readOnly == 1) && (flag != NULL_IF_NOT_EXISTED)){
		CMS_LOG(LL_ERROR, "current app authority of xml share memory is read only, can't use ADD_IF_NOT_EXITED, please use right API & right FLAG!!!\n");
		return NULL;
	}
		
	XML_LOCK(&xmlShmCb->cmsMutex->lock);
	objectList_t *objList = cmsXml_GetObjListByName( xmlShmCb, name);
	XML_UNLOCK(&xmlShmCb->cmsMutex->lock);

	if ( objList != NULL )
	{
		ptr = cmsXml_GetObjectByOID( xmlShmCb, objList->OID, objList->IA, flag );
		cmsXml_FreeObjList( &objList );
		return ptr;
	}
	else
	{
		CMS_LOG(LL_ERROR, " %s get ObjList failed.\n", name );
		return NULL;
	}
}

/*
	description: 
		create new preobj + object from indexnode OID and fill corresponded info in xmlShmCb.
	parameters:
		xmlShmCb: xml shm control block.
		OID: object ID, this OID must be indexnode OID.
		nodeIA: instance array.
	return:
		the new real index object address.
		xmlShmCb->OID, xmlShmCb->IA, xmlShmCb->offset.
	called by: cmsXml_GetObjectByOID()
	example:
		{}
*/
void *cmsXml_AddIndexChildObject( cmsXmlCb_t *xmlShmCb, int OID, uint64_t nodeIA ) /* this OID must be indexnode OID. */
{
	//void *srcObj = NULL;
	objectNode_t *tmpNode = NULL, *srcNode = NULL;
	uint64_t getIAValue = 0, newIAValue = nodeIA;
	cmsoffset_t srcOffset = 0, getOffset = 0, finalOffset = 0, newOffset = 0;
	int depth = 0, newIndex = 1;
	uint32_t getAttr = 0, objectSize = 0;
	void *nodeAdrr = NULL;
	
	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return NULL;
	}
	/* get indexchild node by indexnode. */
	tmpNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, cmsXmlGetPreObjNode( xmlShmCb, cmsXml_GetOffsetByOID( OID ) ) );
	srcNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, tmpNode->child );

	/* get object size from prototype node. */
	objectSize = srcNode->object_size & GET_OBJECT_SIZE_MASK;
	srcOffset = srcNode->object;
	depth = cmsXmlGetIADepth( cmsXmlGetPreObjIA( xmlShmCb, srcOffset ) );
	CMS_LOG(LL_FLOOD, "srcOffset=%d, depth=%d, objectSize=%d\n", srcOffset, depth, objectSize );

	/* get srcObj real address. */
	nodeAdrr = cmsXmlGetObjRealAddr( xmlShmCb, srcOffset );
	if(nodeAdrr == NULL)
		return NULL;

	/* find out which offset we could reuse and what IA value we could use. */
	getOffset = cmsXmlGetPreObjNext( xmlShmCb, srcOffset );
	while( getOffset ) /* continue to check NEXT offset. */
	{
		getIAValue = cmsXmlGetPreObjIA( xmlShmCb, getOffset );
		//printIAArray( getIAValue );
		if ( compareIAByDepth( nodeIA, getIAValue, depth - 1 ) )
		{
#ifdef SUPPORT_MAXNODENUMBER /* support add smaller index number. */
			getAttr = cmsXmlGetPreObjAttr( xmlShmCb, getOffset );
			if ( ( newIndex == cmsXmlGetIAInfo( getIAValue, depth ) ) && ( getAttr & ATTR_NODECONFIGURED ) )
			{
				newIndex++;
			}
#else
			if ( newIndex <= cmsXmlGetIAInfo( getIAValue, depth ) )
			{
				newIAValue = getIAValue;
				newIndex = cmsXmlGetIAInfo( getIAValue, depth );
			}
#endif
		}

		getAttr = cmsXmlGetPreObjAttr( xmlShmCb, getOffset );
		if ( !newOffset && !( getAttr & ATTR_NODECONFIGURED ) ) /* find first nonconfigured index object offset. */
		{
			newOffset = getOffset;
		}
		finalOffset = getOffset;
		getOffset = cmsXmlGetPreObjNext( xmlShmCb, getOffset );
		//printf( "while getOffset=%lu, finalOffset=%lu, newOffset=%lu\n", getOffset, finalOffset, newOffset );
	}

	/* calculate new IA value. */
#ifdef SUPPORT_MAXNODENUMBER /* support add smaller index number. */
	//printf( "newIndex=%d, child_count=%lu\n", newIndex, srcNode->sibling.child_count );
	if ( newIndex > srcNode->sibling.child_count )
	{
		cmsXml_SetCBData( xmlShmCb, 0 );
		return NULL;
	}
	newIAValue = cmsXmlSetIAValue( newIAValue, depth, newIndex );
#else
	newIAValue = cmsXmlSetIAValue( newIAValue, depth, cmsXmlGetIAInfo( newIAValue, depth ) + 1 );
#endif
	newIAValue = cmsXmlSetIAValue( newIAValue, IA_DEPTHNUM, depth );
	//printIAArray( newIAValue );

	/* figure out what position this new index object should be located in. */
	if ( newOffset == 0 ) /* no available reuse space, append new index object to last. */
	{
		newOffset = cmsXml_SetObjDefault( xmlShmCb, srcOffset, OBJECT_CREATE_OBJECT );
		if(newOffset == 0){
			CMS_LOG(LL_ERROR, "add object (%d, %lx ) will exceed max shm size(%u)", OID, nodeIA, X2S_MEMORY_SIZE);
			return NULL;
		}
		if ( finalOffset ) /* this node has NEXT. */
		{
			/* set offset of new index object to NEXT of final index object. */
			cmsXml_SetPreObjNext( xmlShmCb, finalOffset, newOffset );
		}
		else /* this indexchild doesn't have index object. */
		{
			/* set offset of new index object to NEXT of prototype object. */
			cmsXml_SetPreObjNext( xmlShmCb, srcOffset, newOffset );
		}
	}

	cmsXml_SetPreObjIA( xmlShmCb, newOffset, newIAValue );
	/* set active to this new index object. */
	cmsXml_SetPreObjStatus( xmlShmCb, newOffset, INDEX_OBJECT_ACTIVE );

	/* sort newOffset to ordered list. */
	if ( cmsXmlGetPreObjNext( xmlShmCb, srcOffset ) != newOffset ) /* this indexchild has more than one index object. */
	{
		cmsXml_SortNewObject( xmlShmCb, srcOffset, newOffset );
	}

	/* check parents or siblings are existed or not. if not, create it. */
	cmsXml_CheckIndexChildParents( xmlShmCb, srcNode, newIAValue );

	cmsXml_SetCBData( xmlShmCb, newOffset );

	return cmsXmlGetObjRealAddr( xmlShmCb, newOffset );
}

/*
	description: 
		create new preobj + object from indexchild OID with assigned IA and fill corresponded info in xmlShmCb.
	parameters:
		xmlShmCb: xml shm control block.
		OID: object ID, this OID must be indexnode OID.
		IA: instance array.
	return:
		the new real index object address.
		xmlShmCb->OID, xmlShmCb->IA, xmlShmCb->offset.
	called by: cmsXml_GetObjectByOID()
	example:
		{}
*/
void *cmsXml_AddObjectWithAssignIA( cmsXmlCb_t *xmlShmCb, int OID, uint64_t IA )
{
	cmsoffset_t getOffset = 0, finalOffset = 0, newOffset = 0, srcOffset = cmsXml_GetOffsetByOID( OID );
	uint32_t getAttr = 0;

	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return NULL;
	}
	/* find out which offset we could reuse. */
	getOffset = cmsXmlGetPreObjNext( xmlShmCb, srcOffset );
	while( getOffset )
	{
		getAttr = cmsXmlGetPreObjAttr( xmlShmCb, getOffset );
		if ( !newOffset && !( getAttr & ATTR_NODECONFIGURED ) ) /* find first nonconfigured indexchild offset!*/
		{
			newOffset = getOffset;
		}
		if ( compareIAOrder( cmsXmlGetPreObjIA( xmlShmCb, getOffset ), IA ) == 0 )
		{
			if ( getAttr & ATTR_NODECONFIGURED )
			{
				CMS_LOG(LL_ERROR,  "this index object is existed.\n" );
				return NULL;
			}
			else
			{
				newOffset = getOffset;
			}
		}
		finalOffset = getOffset;
		/* continue to check next offset. */
		getOffset = cmsXmlGetPreObjNext( xmlShmCb, getOffset );
		//printf( "while getOffset=%lu, finalOffset=%lu, newOffset=%lu\n", getOffset, finalOffset, newOffset );
	}

	if ( newOffset == 0 ) /* no available reuse space, append new index object to last. */
	{
		newOffset = cmsXml_SetObjDefault( xmlShmCb, srcOffset, OBJECT_CREATE_OBJECT );
		if(newOffset == 0){
			CMS_LOG(LL_ERROR, "add object (%d, %lx) will exceed max shm size(%u)", OID, IA, X2S_MEMORY_SIZE);
			return NULL;
		}
		if ( finalOffset ) /* this node has NEXT. */
		{
			/* set offset of new index object to NEXT of final index object. */
			cmsXml_SetPreObjNext( xmlShmCb, finalOffset, newOffset );
		}
		else /* this indexchild doesn't have index object. */
		{
			/* set offset of new index object to NEXT of prototype object. */
			cmsXml_SetPreObjNext( xmlShmCb, srcOffset, newOffset );
		}
	}

	cmsXml_SetPreObjIA( xmlShmCb, newOffset, IA );
	/* set active to this new index object. */
	cmsXml_SetPreObjStatus( xmlShmCb, newOffset, INDEX_OBJECT_ACTIVE );

	/* sort newOffset to ordered list. */
	if ( cmsXmlGetPreObjNext( xmlShmCb, srcOffset ) != newOffset ) /* this indexchild has more than one index object. */
	{
		cmsXml_SortNewObject( xmlShmCb, srcOffset, newOffset );
	}

	/* check parents or siblings are existed or not. if not, create it. */
	cmsXml_CheckIndexChildParents( xmlShmCb, (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, cmsXmlGetPreObjNode( xmlShmCb, newOffset ) ), IA );

	cmsXml_SetCBData( xmlShmCb, newOffset );

	return cmsXmlGetObjRealAddr( xmlShmCb, newOffset );
}

/* delete object and put deleted object to tail of list. */
int cmsXml_DelObject( cmsXmlCb_t *xmlShmCb, int flag )
{
	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return CMS_NOK;
	}
	
	cmsoffset_t getOffset = 0, preOffset = 0, finalOffset = 0, targetOffset = xmlShmCb->offset, srcOffset = cmsXml_GetOffsetByOID( xmlShmCb->OID );

	if ( cmsXmlGetPreObjAttr( xmlShmCb, xmlShmCb->offset ) & ATTR_ALWAYSACTIVE )
	{
		/* we could not remove this index object. */
		return CMS_OK;
	}
	//printf( "delete %s\n", cmsXml_getFullPathByID( xmlShmCb, xmlShmCb->offset ) );

	getOffset = cmsXmlGetPreObjNext( xmlShmCb, srcOffset );
	if ( ( getOffset == targetOffset ) && ( cmsXmlGetPreObjNext( xmlShmCb, getOffset ) == 0 ) ) /* this indexchild has only one index object, just set nonconfigured. */
	{
		//cmsXml_SetPreObjNonConfig( xmlShmCb, targetOffset );
	}
	else
	{
		while ( getOffset )
		{
			if ( ( preOffset == 0 ) && ( getOffset == targetOffset ) ) /* del obj is first obj. */
			{
				preOffset = srcOffset;
			}
			if ( cmsXmlGetPreObjNext( xmlShmCb, getOffset ) == targetOffset ) /* get preOffset which NEXT is targetOffset. */
			{
				preOffset = getOffset;
			}
			finalOffset = getOffset; /* continue to remember last offset. */
			/* continue to check next offset. */
			getOffset = cmsXmlGetPreObjNext( xmlShmCb, getOffset );
		}

		if ( finalOffset != targetOffset ) /* because del obj has NEXT value, write this value to preOffset and move targetOffset to last of list. */
		{
			/* NEXT of preOffset points to NEXT of del obj. */
			cmsXml_SetPreObjNext( xmlShmCb, preOffset, cmsXmlGetPreObjNext( xmlShmCb, targetOffset ) );
			/* NEXT of finalOffset is del obj. */
			cmsXml_SetPreObjNext( xmlShmCb, finalOffset, targetOffset );
			cmsXml_SetPreObjNext( xmlShmCb, targetOffset, 0 );
		}
	}

	if ( flag == INDEX_OBJECT_INACTIVE ) /* restore target object data to default value. */
	{
		cmsXml_SetObjDefault( xmlShmCb, targetOffset, OBJECT_RESTORE_DATA );
	}
	else if ( flag == INDEX_OBJECT_INACTIVE_NORESET )
	{
		CMS_LOG(LL_ERROR,  "del action: INDEX_OBJECT_INACTIVE_NORESET.\n" );
	}

	cmsXml_SetPreObjNonConfig( xmlShmCb, targetOffset );

	return CMS_OK;
}

/* delete object by OID and put deleted object to tail of list. */
int cmsXml_DelObjectByOID( cmsXmlCb_t *xmlShmCb, int OID, uint64_t IA )
{
	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return CMS_NOK;
	}

	if(xmlShmCb->readOnly == 1){
		CMS_LOG(LL_ERROR, "current app authority of xml share memory is read only, can't use direct set api, please use right API!!!\n");
		return CMS_NOK;
	}
	
	void *ptr = cmsXml_GetObjectByOID( xmlShmCb, OID, IA, NULL_IF_NOT_EXISTED );

	if ( ptr != NULL )
	{
		CMS_LOG(LL_FLOOD,  "del object OID %d start.\n", OID );
		//printIAArray( IA );
		cmsXml_SetPreObjStatus( xmlShmCb, xmlShmCb->offset, INDEX_OBJECT_INACTIVE );
		return CMS_OK;
	}
	else
	{
		CMS_LOG(LL_FLOOD, "del object OID %d not exsit.\n", OID );
		//printIAArray( IA );
		return CMS_NOK;
	}
}

/* delete object by name and put deleted object to tail of list. */
int cmsXml_DelObjectByName( cmsXmlCb_t *xmlShmCb, char *name )
{
	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return CMS_NOK;
	}

	if(xmlShmCb->readOnly == 1){
		CMS_LOG(LL_ERROR, "current app authority of xml share memory is read only, can't use direct set api, please use right API!!!\n");
		return CMS_NOK;
	}
	
	void *ptr = cmsXml_GetObjectByName( xmlShmCb, name, NULL_IF_NOT_EXISTED );

	if ( ptr != NULL )
	{
		CMS_LOG(LL_FLOOD, "del object %s start.\n", name );
		cmsXml_SetPreObjStatus( xmlShmCb, xmlShmCb->offset, INDEX_OBJECT_INACTIVE );
		return CMS_OK;
	}
	else
	{
		CMS_LOG(LL_FLOOD, "del object %s not exsit.\n", name );
		return CMS_NOK;
	}
}

/* delete object by name and put deleted object to tail of list. */
int cmsXml_DelObjectByOffset( cmsXmlCb_t *xmlShmCb, cmsoffset_t offset )
{
	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return CMS_NOK;
	}

	if(xmlShmCb->readOnly == 1){
		CMS_LOG(LL_ERROR, "current app authority of xml share memory is read only, can't use direct set api, please use right API!!!\n");
		return CMS_NOK;
	}
	
	objectNode_t *tmpNode = NULL, *srcNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, cmsXmlGetPreObjNode( xmlShmCb, offset ) );

	if ( srcNode != NULL )
	{
		xmlShmCb->OID = cmsXml_GetOIDByOffset( xmlShmCb, srcNode->object );
		xmlShmCb->IA = cmsXmlGetPreObjIA( xmlShmCb, offset );
		xmlShmCb->offset = offset;
		//printf( "del object %lu start.\n", offset );
		//printIAArray( xmlShmCb->IA );
		cmsXml_DelObject( xmlShmCb, INDEX_OBJECT_INACTIVE );
		if ( srcNode->child )
		{
			tmpNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, srcNode->child );
			cmsXml_CheckDelObject( xmlShmCb, tmpNode, cmsXml_GetOIDByOffset( xmlShmCb, tmpNode->object ), cmsXmlGetPreObjIA( xmlShmCb, offset ) );
		}
		cmsXml_SetCBData( xmlShmCb, offset );
		return CMS_OK;
	}
	else
	{
		//printf( "del object %lu failed.\n", offset );
		CMS_LOG(LL_FLOOD, "offset %u not valied.\n", offset );
		return CMS_NOK;
	}
}

int cmsXml_CheckDelObject( cmsXmlCb_t *xmlShmCb, objectNode_t *node, int OID, uint64_t IA )
{
	void *ptr = NULL;
	objectNode_t *childNode = NULL;
	int depth = 0;
	cmsoffset_t getOffset = 0;
	uint64_t tmpIA = 0;

	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return CMS_NOK;
	}

	if ( ( node->attributes & ATTR_INDEXCHILD ) == ATTR_INDEXCHILD )
	{
		depth = cmsXmlGetIADepth( cmsXmlGetPreObjIA( xmlShmCb, node->object ) );

		/* start to find the next node which belonged to this parents IA. */
		getOffset = cmsXmlGetPreObjNext( xmlShmCb, node->object );
		//printf( "OID=%d, getOffset=%lu, depth=%d\n", OID, getOffset, depth );
		while ( getOffset )
		{
			if ( compareIAByDepth( IA, cmsXmlGetPreObjIA( xmlShmCb, getOffset ), depth - 1 ) )
			{
				tmpIA = cmsXmlGetPreObjIA( xmlShmCb, getOffset );
				if ( node->attributes & ATTR_OBJECTNODE )
				{
					ptr = cmsXml_GetObjectByOID( xmlShmCb, OID, tmpIA, NULL_IF_NOT_EXISTED );
					if ( ptr != NULL )
					{
						//printf( "ptr=%lu, attr=%lu, OID=%d\n", cmsXmlGetPtrOffset( xmlShmCb, ptr ), cmsXmlGetPreObjAttr( xmlShmCb, cmsXmlGetPtrOffset( xmlShmCb, ptr ) ), OID );
						if ( !( cmsXmlGetPreObjAttr( xmlShmCb, cmsXmlGetPtrOffset( xmlShmCb, ptr ) ) & ATTR_ALWAYSACTIVE ) )
						{
							cmsXml_SetObjDefault( xmlShmCb, xmlShmCb->offset, OBJECT_RESTORE_DATA );
							cmsXml_SetPreObjNonConfig( xmlShmCb, xmlShmCb->offset );
							//printf( "delete %s\n", cmsXml_getFullPathByID( xmlShmCb, xmlShmCb->offset ) );
						}
					}
				}
				if ( node->child )
				{
					childNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, node->child );
					cmsXml_CheckDelObject( xmlShmCb, childNode, cmsXml_GetOIDByOffset( xmlShmCb, childNode->object ), tmpIA );
				}
			}

			/* continue get next node. */
			getOffset = cmsXmlGetPreObjNext( xmlShmCb, getOffset );
		}
	}
	else
	{
		if ( node->attributes & ATTR_OBJECTNODE )
		{
			ptr = cmsXml_GetObjectByOID( xmlShmCb, OID, IA, NULL_IF_NOT_EXISTED );
			if ( ptr != NULL )
			{
				//printf( "ptr=%lu, attr=%lu, OID=%d\n", cmsXmlGetPtrOffset( xmlShmCb, ptr ), cmsXmlGetPreObjAttr( xmlShmCb, cmsXmlGetPtrOffset( xmlShmCb, ptr ) ), OID );
				if ( !( cmsXmlGetPreObjAttr( xmlShmCb, cmsXmlGetPtrOffset( xmlShmCb, ptr ) ) & ATTR_ALWAYSACTIVE ) )
				{
					cmsXml_SetObjDefault( xmlShmCb, xmlShmCb->offset, OBJECT_RESTORE_DATA );
					cmsXml_SetPreObjNonConfig( xmlShmCb, xmlShmCb->offset );
					//printf( "delete %s\n", cmsXml_getFullPathByID( xmlShmCb, xmlShmCb->offset ) );
				}
			}
		}
		if ( node->child )
		{
			childNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, node->child );
			cmsXml_CheckDelObject( xmlShmCb, childNode, cmsXml_GetOIDByOffset( xmlShmCb, childNode->object ), IA );
		}

		if ( node->sibling.tree.prev )
		{
			childNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, node->sibling.tree.prev );
			cmsXml_CheckDelObject( xmlShmCb, childNode, cmsXml_GetOIDByOffset( xmlShmCb, childNode->object ), IA );
		}

		if ( node->sibling.tree.next )
		{
			childNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, node->sibling.tree.next );
			cmsXml_CheckDelObject( xmlShmCb, childNode, cmsXml_GetOIDByOffset( xmlShmCb, childNode->object ), IA );
		}
	}

	return CMS_OK;
}

/*check string is index child num or not. -1 error, 0 string,  1 num*/
static int isIndexNum(char *str)
{
	int len = 0;
	int i = 0;
	
	if(str == NULL)
		return -1;
	
	len = strlen(str);
	for(i = 0; i < len; i++){
		if(!isdigit(str[i]))
			return 0;
	}

	return 1;
}

/*
	description: 
		get objList by name.
	parameters:
		xmlShmCb: xml shm control block.
		name: full object path name.
	return:
		the pointer of objList or NULL.
	called by: cmsXml_GetObjectByName().
	example:
		{}
*/
objectList_t *cmsXml_GetObjListByName( cmsXmlCb_t *xmlShmCb, char *name )
{
	void *ptr = NULL;
	char *savePtr = NULL;
	objectNode_t *tmpNode = NULL;
	char *strPtr = NULL;
	char tmpStr[ BUFLEN_256 ] = { 0 }, newStr[ BUFLEN_256 ] = { 0 };
	int tmpNum = 0, depth = 0;
	uint64_t targetIA = 0;

	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlShmCb is NULL\n" );
		return NULL;
	}

	if(name == NULL){
		CMS_LOG(LL_ERROR, "object name is NULL\n" );
		return NULL;
	}

	//printf( "name=%s\n", name );
	strncpy( tmpStr, name, strlen( name ) );
	strPtr = strtok_r( tmpStr, ".", &savePtr);
	while( strPtr )
	{
		tmpNum = atoi( strPtr );
		if ( ( tmpNum > 0 ) && ( tmpNum < 256 ) ) /* find index, increase depth and set IA value with index. */
		{
			depth++;
			targetIA = cmsXmlSetIAValue( targetIA, depth, tmpNum );
			strcat( newStr, "i" );
		}
		else
		{
			if(isIndexNum(strPtr) == 1){
				CMS_LOG(LL_ERROR, "wrong object name, index num %d is not in the range(1~255).\n", tmpNum);
				return NULL;
			}
		
			strcat( newStr, strPtr );
		}

		strPtr = strtok_r( NULL, ".", &savePtr);
		if ( strPtr != NULL )
		{
			strcat( newStr, "." );
		}
	}
	targetIA = cmsXmlSetIAValue( targetIA, IA_DEPTHNUM, depth );

	/* use new string without index to get prototype object. */
	ptr = cmsXml_getObjectByProtoName( xmlShmCb, newStr);
	if ( ptr != NULL )
	{
		/* if the depth of prototype is the same as new string's, return the pointer of objList. */
		if ( cmsXmlGetIADepth( cmsXmlGetPreObjIA( xmlShmCb, cmsXmlGetPtrOffset( xmlShmCb, ptr ) ) ) == ( cmsXmlGetIADepth( targetIA ) + 1 ) )
		{
			/* it is indexnode OID, return indexnode OID. */
			tmpNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, xmlShmCb->objectNode->parent );
			return cmsXml_CreateObjListNode( cmsXml_GetOIDByOffset( xmlShmCb, tmpNode->object ), targetIA );
		}
		else
		{
			return cmsXml_CreateObjListNode( cmsXml_GetOIDByOffset( xmlShmCb, cmsXmlGetPtrOffset( xmlShmCb, ptr ) ), targetIA );
		}
	}
	else
	{
		//printf( "%s: %s get cmsXml_getObjectByProtoName failed.\n", __FUNCTION__, name );
		return NULL;
	}
}

objectList_t *cmsXml_GetObjListByOID( cmsXmlCb_t *xmlShmCb, int OID )
{
	objectList_t *objList = NULL, *newNode = NULL;

	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return NULL;
	}
	objectNode_t *tmpNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, cmsXmlGetPreObjNode( xmlShmCb, cmsXml_GetOffsetByOID( OID ) ) );
	cmsoffset_t getOffset = 0;

	if ( tmpNode == NULL )
	{
		return NULL;
	}
	else
	{
		if ( tmpNode->attributes & ATTR_INDEXNODE )
		{
			tmpNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, tmpNode->child );
		}
		/* prototype object offset. */
		getOffset = tmpNode->object;
		/* first NEXT offset of prototype object. */
		getOffset = cmsXmlGetPreObjNext( xmlShmCb, getOffset );
		while( getOffset )
		{
			if ( cmsXmlGetPreObjAttr( xmlShmCb, getOffset ) & ATTR_NODECONFIGURED )
			{
				newNode = cmsXml_CreateObjListNode( OID, cmsXmlGetPreObjIA( xmlShmCb, getOffset ) );
				OBJECT_LIST_ENQUEUE( objList, newNode );
			}
			getOffset = cmsXmlGetPreObjNext( xmlShmCb, getOffset );
		}
		return objList;
	}
}

objectList_t *cmsXml_GetObjListByOIDIA( cmsXmlCb_t *xmlShmCb, int OID, uint64_t IA, int depth )
{
	objectList_t *objList = NULL, *newNode = NULL;

	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return NULL;
	}
	
	objectNode_t *tmpNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, cmsXmlGetPreObjNode( xmlShmCb, cmsXml_GetOffsetByOID( OID ) ) );
	cmsoffset_t getOffset = 0;

	if ( tmpNode == NULL || ( depth < 0 ) )
	{
		return NULL;
	}
	else
	{
		if ( tmpNode->attributes & ATTR_INDEXNODE )
		{
			tmpNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, tmpNode->child );
		}
		/* prototype object offset. */
		getOffset = tmpNode->object;
		/* first NEXT offset of prototype object. */
		getOffset = cmsXmlGetPreObjNext( xmlShmCb, getOffset );
		while( getOffset )
		{
			if ( compareIAByDepth( IA, cmsXmlGetPreObjIA( xmlShmCb, getOffset ), depth ) && ( cmsXmlGetPreObjAttr( xmlShmCb, getOffset ) & ATTR_NODECONFIGURED ) )
			{
				newNode = cmsXml_CreateObjListNode( OID, cmsXmlGetPreObjIA( xmlShmCb, getOffset ) );
				OBJECT_LIST_ENQUEUE( objList, newNode );
			}
			getOffset = cmsXmlGetPreObjNext( xmlShmCb, getOffset );
		}
		return objList;
	}
}

objectList_t *cmsXml_GetFullChildList( cmsXmlCb_t *xmlShmCb, int OID, uint64_t IA )
{
	objectList_t *objList = NULL;
	objectNode_t *childNode = NULL;
	uint32_t childObjID = 0;

	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return NULL;
	}
	objectNode_t *srcNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, cmsXmlGetPreObjNode( xmlShmCb, xmlShmCb->offset ) );

	if ( srcNode->child )
	{	
		childNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, srcNode->child );
		childObjID = cmsXml_GetOIDByOffset( xmlShmCb, childNode->object );
		cmsXml_GetObjectChildList( xmlShmCb, childNode, childObjID, IA, &objList );
	}
	//cmsXml_FreeObjListNode( &objList, OID, IA );

	return objList;
}

objectList_t *cmsXml_GetOneLayerChildList( cmsXmlCb_t *xmlShmCb, int OID, uint64_t IA )
{
	objectList_t *objList = NULL;
	objectNode_t *childNode = NULL;
	uint32_t childObjID = 0;

	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return NULL;
	}
	objectNode_t *srcNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, cmsXmlGetPreObjNode( xmlShmCb, xmlShmCb->offset ) );

	if ( srcNode->child )
	{	
		childNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, srcNode->child );
		childObjID = cmsXml_GetOIDByOffset( xmlShmCb, childNode->object );
		cmsXml_GetObjChildList_OneLayer( xmlShmCb, childNode, childObjID, IA, &objList );
	}
	//cmsXml_FreeObjListNode( &objList, OID, IA );

	return objList;
}


/* create new objList space with OID and IA. */
objectList_t *cmsXml_CreateObjListNode( int OID, uint64_t IA )
{
	objectList_t *newNode = (objectList_t *)calloc( sizeof( objectList_t ), 1 );

	newNode->OID = OID;
	newNode->IA = IA;

	return newNode;
}

void cmsXml_FreeObjListNode( objectList_t** objList, int OID, uint64_t IA )
{
	objectList_t *nextNode = NULL, *newNode = *objList;
	while ( newNode )
	{
		nextNode = newNode->next;
		if ( ( newNode->OID == OID ) && ( newNode->IA == IA ) )
		{
			OBJECT_LIST_DEQUEUE( *objList, newNode );
			free ( newNode );
			return;
		}
		newNode = nextNode;
	}
}

void cmsXml_FreeObjList( objectList_t** objList )
{
	objectList_t *nextNode = NULL, *newNode = *objList;
	while ( newNode )
	{
		nextNode = newNode->next;
		OBJECT_LIST_DEQUEUE( *objList, newNode );
		free ( newNode );
		newNode = nextNode;
	}
}

/*get all childs and all descendants*/
int cmsXml_GetObjectChildList( cmsXmlCb_t *xmlShmCb, objectNode_t *node, int OID, uint64_t IA, objectList_t **list )
{
	void *ptr = NULL;
	objectNode_t *childNode = NULL;
	int depth = 0;
	cmsoffset_t getOffset = 0;
	uint64_t tmpIA = 0;
	objectList_t *listNode = NULL;
	
	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return CMS_NOK ;
	}
	
	if ( ( node->attributes & ATTR_INDEXCHILD ) == ATTR_INDEXCHILD )
	{
		depth = cmsXmlGetIADepth( cmsXmlGetPreObjIA( xmlShmCb, node->object ) );

		/* start to find the next node which belonged to this parents IA. */
		getOffset = cmsXmlGetPreObjNext( xmlShmCb, node->object );
		//printf( "OID=%d, getOffset=%lu, depth=%d\n", OID, getOffset, depth );
		while ( getOffset )
		{
			if ( compareIAByDepth( IA, cmsXmlGetPreObjIA( xmlShmCb, getOffset ), depth - 1 ) )
			{
				tmpIA = cmsXmlGetPreObjIA( xmlShmCb, getOffset );
				if ( node->attributes & ATTR_OBJECTNODE )
				{
					ptr = cmsXml_GetObjectByOID( xmlShmCb, OID, tmpIA, NULL_IF_NOT_EXISTED );
					if ( ptr != NULL )
					{
						listNode = cmsXml_CreateObjListNode( xmlShmCb->OID, xmlShmCb->IA );
						OBJECT_LIST_ENQUEUE_BY_DEPTH( *list, listNode );
						//printf( "enqueue %s\n", cmsXml_getFullPathByID( xmlShmCb, xmlShmCb->offset ) );
					}
				}
				if ( node->child )
				{
					childNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, node->child );
					cmsXml_GetObjectChildList( xmlShmCb, childNode, cmsXml_GetOIDByOffset( xmlShmCb, childNode->object ), tmpIA, list );
				}
			}

			/* continue get next node. */
			getOffset = cmsXmlGetPreObjNext( xmlShmCb, getOffset );
		}
	}
	else
	{
		if ( node->attributes & ATTR_OBJECTNODE )
		{
			ptr = cmsXml_GetObjectByOID( xmlShmCb, OID, IA, NULL_IF_NOT_EXISTED );
			if ( ptr != NULL )
			{
				listNode = cmsXml_CreateObjListNode( xmlShmCb->OID, xmlShmCb->IA );
				OBJECT_LIST_ENQUEUE_BY_DEPTH( *list, listNode );
				//printf( "enqueue %s\n", cmsXml_getFullPathByID( xmlShmCb, xmlShmCb->offset ) );
			}
		}
		if ( node->child )
		{
			childNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, node->child );
			cmsXml_GetObjectChildList( xmlShmCb, childNode, cmsXml_GetOIDByOffset( xmlShmCb, childNode->object ), IA, list );
		}

		if ( node->sibling.tree.prev )
		{
			childNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, node->sibling.tree.prev );
			cmsXml_GetObjectChildList( xmlShmCb, childNode, cmsXml_GetOIDByOffset( xmlShmCb, childNode->object ), IA, list );
		}

		if ( node->sibling.tree.next )
		{
			childNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, node->sibling.tree.next );
			cmsXml_GetObjectChildList( xmlShmCb, childNode, cmsXml_GetOIDByOffset( xmlShmCb, childNode->object ), IA, list );
		}
	}

	return 1;
}

/*just get object's child but not all descendants*/
int cmsXml_GetObjChildList_OneLayer( cmsXmlCb_t *xmlShmCb, objectNode_t *node, int OID, uint64_t IA, objectList_t **list )
{
	void *ptr = NULL;
	objectNode_t *childNode = NULL;
	int depth = 0;
	cmsoffset_t getOffset = 0;
	uint64_t tmpIA = 0;
	objectList_t *listNode = NULL;
	
	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return CMS_NOK ;
	}
	
	if ( ( node->attributes & ATTR_INDEXCHILD ) == ATTR_INDEXCHILD )
	{
		depth = cmsXmlGetIADepth( cmsXmlGetPreObjIA( xmlShmCb, node->object ) );

		/* start to find the next node which belonged to this parents IA. */
		getOffset = cmsXmlGetPreObjNext( xmlShmCb, node->object );
		//printf( "OID=%d, getOffset=%lu, depth=%d\n", OID, getOffset, depth );
		while ( getOffset )
		{
			if ( compareIAByDepth( IA, cmsXmlGetPreObjIA( xmlShmCb, getOffset ), depth - 1 ) )
			{
				tmpIA = cmsXmlGetPreObjIA( xmlShmCb, getOffset );
				if ( node->attributes & ATTR_OBJECTNODE )
				{
					ptr = cmsXml_GetObjectByOID( xmlShmCb, OID, tmpIA, NULL_IF_NOT_EXISTED );
					if ( ptr != NULL )
					{
						listNode = cmsXml_CreateObjListNode( xmlShmCb->OID, xmlShmCb->IA );
						OBJECT_LIST_ENQUEUE_BY_DEPTH( *list, listNode );
						//printf( "enqueue %s\n", cmsXml_getFullPathByID( xmlShmCb, xmlShmCb->offset ) );
					}
				}
			}

			/* continue get next node. */
			getOffset = cmsXmlGetPreObjNext( xmlShmCb, getOffset );
		}
	}
	else
	{
		if ( node->attributes & ATTR_OBJECTNODE )
		{
			ptr = cmsXml_GetObjectByOID( xmlShmCb, OID, IA, NULL_IF_NOT_EXISTED );
			if ( ptr != NULL )
			{
				listNode = cmsXml_CreateObjListNode( xmlShmCb->OID, xmlShmCb->IA );
				OBJECT_LIST_ENQUEUE_BY_DEPTH( *list, listNode );
				//printf( "enqueue %s\n", cmsXml_getFullPathByID( xmlShmCb, xmlShmCb->offset ) );
			}
		}

		if ( node->sibling.tree.prev )
		{
			childNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, node->sibling.tree.prev );
			cmsXml_GetObjChildList_OneLayer( xmlShmCb, childNode, cmsXml_GetOIDByOffset( xmlShmCb, childNode->object ), IA, list );
		}

		if ( node->sibling.tree.next )
		{
			childNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, node->sibling.tree.next );
			cmsXml_GetObjChildList_OneLayer( xmlShmCb, childNode, cmsXml_GetOIDByOffset( xmlShmCb, childNode->object ), IA, list );
		}
	}

	return 1;
}


/* check siblings are existed or not. if not, create it. */
void cmsXml_CheckIndexChildSibling( cmsXmlCb_t *xmlShmCb, objectNode_t *node, uint64_t IA )
{
	objectNode_t *tmpNode = node;
	
	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return;
	}
	
	if ( tmpNode != NULL )
	{
		if ( tmpNode->sibling.tree.prev )
		{
			cmsXml_CheckIndexChildSibling( xmlShmCb, (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, tmpNode->sibling.tree.prev ), IA );
		}

		if ( tmpNode->sibling.tree.next )
		{
			cmsXml_CheckIndexChildSibling( xmlShmCb, (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, tmpNode->sibling.tree.next ), IA );
		}

		if ( ( tmpNode->attributes == 0 ) || ( tmpNode->attributes == ATTR_NODECONFIGURED ) )
		{
			tmpNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, tmpNode->child );
			if( tmpNode != NULL ){
				if ( tmpNode->sibling.tree.prev )
				{
					cmsXml_CheckIndexChildSibling( xmlShmCb, (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, tmpNode->sibling.tree.prev ), IA );
				}
				if ( tmpNode->sibling.tree.next )
				{
					cmsXml_CheckIndexChildSibling( xmlShmCb, (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, tmpNode->sibling.tree.next ), IA );
				}
			}
		}

		if ( ( tmpNode->attributes & ATTR_OBJECTNODE ) && !( tmpNode->attributes & ATTR_INDEXNODE ) && !( tmpNode->attributes & ATTR_INDEXCHILD ) )
		{
			cmsXml_GetObjectByOID( xmlShmCb, cmsXml_GetOIDByOffset( xmlShmCb, tmpNode->object ), IA, ADD_IF_NOT_EXISTED );
		}
	}
}

/* check parents are existed or not. if not, create it. */
void cmsXml_CheckIndexChildParents( cmsXmlCb_t *xmlShmCb, objectNode_t *node, uint64_t IA )
{
	int depth = 0;
	uint64_t getIAValue = IA;
	objectNode_t *tmpNode = node;

	
	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return;
	}
	
	depth = cmsXmlGetIADepth( getIAValue );
	while ( depth )
	{
		if ( (tmpNode != NULL) && (tmpNode->attributes & ATTR_INDEXCHILD))
		{
			getIAValue = cmsXmlSetIAValue( getIAValue, depth + 1, 0 );
			cmsXml_GetObjectByOID( xmlShmCb, cmsXml_GetOIDByOffset( xmlShmCb, tmpNode->object ), getIAValue, ADD_IF_NOT_EXISTED );

			cmsXml_CheckIndexChildSibling( xmlShmCb, (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, tmpNode->child ), getIAValue );
			getIAValue = cmsXmlSetIAValue( getIAValue, IA_DEPTHNUM, --depth );
		}

		if((tmpNode != NULL) && (tmpNode->attributes & ATTR_OBJECTNODE)){
			getIAValue = cmsXmlSetIAValue( getIAValue, depth + 1, 0 );
			cmsXml_GetObjectByOID( xmlShmCb, cmsXml_GetOIDByOffset( xmlShmCb, tmpNode->object ), getIAValue, ADD_IF_NOT_EXISTED );
			cmsXml_CheckIndexChildSibling( xmlShmCb, (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, tmpNode->child ), getIAValue );
		}

		if(tmpNode != NULL){
			tmpNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, tmpNode->parent );
			if ((tmpNode != NULL) && (( tmpNode->attributes == 0 ) || ( tmpNode->attributes == ATTR_NODECONFIGURED )))
			{
				tmpNode = (objectNode_t *)cmsXmlGetObjRealAddr( xmlShmCb, tmpNode->parent );
			}
		}
	}
}


/*
	Description: 
		use to get the node's all parameter names
	Parameters:
		xmlShmCb:	xml shm control block
		objectPath: the object full path
	return:
		return a double pointer point to the parameter pointer array
		p1, p2, p3, p4.....
	note:
		after using, you MUST call cmsXml_FreeParameterNameBuffer() 
		to free the memory of parameter name pointer
*/

void **cmsXml_GetParameterNameByObjectName(cmsXmlCb_t *xmlShmCb, char *objectPath){
	void **name, *object, *value;
	int i = 0;
	uint16_t count = 0;

	
	if(xmlShmCb == NULL){
		CMS_LOG(LL_ERROR, "xmlshmcb is NULL\n");
		return NULL;
	}
	
	object = cmsXml_GetObjectByName(xmlShmCb, objectPath, NULL_IF_NOT_EXISTED);
	if(object){
		if ((xmlShmCb->objectNode->attributes & ATTR_OBJECTNODE) != ATTR_OBJECTNODE){
			CMS_LOG(LL_ERROR, "cmsXml_GetParameterNameByObjectName is not a object node\r\n");
			return NULL;	/*the id is not object node*/
		}
		name = malloc(sizeof(void *)*xmlShmCb->objectNode->meta_count);
		memset(name, 0, sizeof(void *)*xmlShmCb->objectNode->meta_count);
		value = name;
		for (i = 1; i < (xmlShmCb->objectNode->meta_count + 1); i++){
			*name = cmsXml_getParameterNamePtr(xmlShmCb, xmlShmCb->objectNode, i);
			if (*name == NULL)
				continue;
			name++;
			count++;
		}
		
		xmlShmCb->meta_count = count;
		return value;
	}else{
		return NULL;
	}
}

/*
	Description: 
		use to copy object value from node to node, including descendants
	Parameters:
		xmlShmCb:	xml shm control block
		src: src node
		dst: dst node
		flag: use to distinguish copy node to node or reset value from i node to other node
				#define COPY_OBJECT_VALUE		1
				#define RESET_INDEXCHILD_OBJECT_VALUE	0
	return:
		return CMS_OK
	call by:

*/
int cmsXml_CopyRdmObjectNodeToDstRdmNode(cmsXmlCb_t *srcrdmCB, cmsXmlCb_t *dstrdmCB,objectNode_t *src, objectNode_t *dst, int flag){
	void *object, *sobject, *dobject;
	char *metaAddr, *meta_ptr;//, *name;
	cmsoffset_t metaOffset, paraOffset, attrOffset;
	uint16_t meta_count;
	uint8_t meta_len = 0;
	uint32_t type_size = 0;
	uint32_t attr = 0;
	int size = 0;
	objectList_t *srcobjList = NULL, *dstobjList = NULL;
	objectNode_t *srcNode = NULL, *dstNode = NULL;
	uint64_t IAValue = 0;
	int OID = 0;

	CMS_LOG(LL_FLOOD, "enter\n");
	
	if(srcrdmCB == NULL || dstrdmCB == NULL || src == NULL || dst == NULL){
		CMS_LOG(LL_ERROR, "func param is NULL\n");
		return CMS_NOK;
	}

	if(srcrdmCB->readOnly == 1 || dstrdmCB->readOnly == 1){
		CMS_LOG(LL_ERROR, "current app authority of xml share memory is read only, can't use direct set api, please use right API!!!\n");
		return CMS_NOK;
	}
	
	OID = srcrdmCB->OID;
	IAValue = srcrdmCB->IA;

	dstobjList = cmsXml_GetFullChildList(dstrdmCB, OID, IAValue);
	srcobjList = cmsXml_GetFullChildList(srcrdmCB, OID, IAValue);
	while(dstobjList) {
		object = cmsXml_GetObjectByOID(dstrdmCB, dstobjList->OID, dstobjList->IA, NULL_IF_NOT_EXISTED);
		if(object != NULL){
			if(cmsXml_GetObjectByOID(srcrdmCB, dstobjList->OID, dstobjList->IA, NULL_IF_NOT_EXISTED) == NULL){
				cmsXml_SetPreObjStatus(dstrdmCB, dstrdmCB->offset, INDEX_OBJECT_INACTIVE );
			}
		}
		if(dstobjList->next == NULL){
			break;
		}
		dstobjList = dstobjList->next;
	}
	while(dstobjList) {
		if(dstobjList->prev == NULL){
			cmsXml_FreeObjList(&dstobjList);
			break;
		}
		dstobjList = dstobjList->prev;
	}

	while(srcobjList) {
		object = cmsXml_GetObjectByOID(srcrdmCB, srcobjList->OID, srcobjList->IA, NULL_IF_NOT_EXISTED);
		if(object != NULL){
			if(cmsXml_GetObjectByOID(dstrdmCB, srcobjList->OID, srcobjList->IA, ADD_IF_NOT_EXISTED) == NULL){
			}
		}
		if(srcobjList->next == NULL){
			break;
		}
		srcobjList = srcobjList->next;
	}

	while(srcobjList) {
		sobject = cmsXml_GetObjectByOID(srcrdmCB, srcobjList->OID, srcobjList->IA, NULL_IF_NOT_EXISTED);
		if(sobject != NULL){
			dobject	= cmsXml_GetObjectByOID(dstrdmCB, srcobjList->OID, srcobjList->IA, NULL_IF_NOT_EXISTED);
			srcNode = srcrdmCB->objectNode;
			dstNode = dstrdmCB->objectNode;
			if (flag == RESET_INDEXCHILD_OBJECT_VALUE){
				if ((dstNode->attributes & ATTR_ALWAYSACTIVE) != ATTR_ALWAYSACTIVE){
					dstNode->attributes &= ~ATTR_NODECONFIGURED;
				}
			}
			else if (flag == COPY_OBJECT_VALUE){
				dstNode->attributes = srcNode->attributes;
			}

			if (dstNode->object_size == 0){
				srcobjList = srcobjList->next;
				continue;
			}
			//sobject = cmsXmlGetObjRealAddr(srcrdmCB, NTOHDL(srcNode->object));
			//dobject = cmsXmlGetObjRealAddr(dstrdmCB, NTOHDL(dstNode->object));
			meta_count = NTOHS(srcNode->meta_count);
			//memcpy(object, sobject, node->object_size);

			memcpy(dobject, sobject, NTOHL(srcNode->config_size));
			metaAddr = sobject -sizeof(cmsoffset_t);
			metaOffset = *((cmsoffset_t *)metaAddr);
			meta_ptr = cmsXmlGetObjRealAddr(srcrdmCB, NTOHDL(metaOffset));
			while(meta_count)
			{
				meta_len = *((uint8_t *)meta_ptr);
				if (meta_len != PADDING_META_LEN){
					type_size = NTOHL(*((uint32_t *)(meta_ptr + meta_len - sizeof(uint32_t))));
					paraOffset = NTOHDL(*((cmsoffset_t *)(meta_ptr + meta_len - (sizeof(cmsoffset_t)*2+sizeof(uint32_t)))));
					attrOffset = NTOHDL(*((cmsoffset_t *)(meta_ptr + meta_len - (sizeof(cmsoffset_t)*1+sizeof(uint32_t)))));
					attr = NTOHL(*((uint32_t *)(sobject+attrOffset)));
					if ((attr & PARAMETER_ATTR_CONFIG) != PARAMETER_ATTR_CONFIG) //Ex:interface name don't want user to modify, so its' value will be non-configure and read-only
					{
						if ((attr & PARAMETER_ATTR_READONLY) != PARAMETER_ATTR_READONLY){
							size = (int)(type_size & ~((uint32_t)PARAMETER_TYPE_CLASS_BITS));
							memcpy((dobject+paraOffset), (sobject+paraOffset), size);
						}
					}
				}
				meta_ptr = meta_ptr + meta_len;
				meta_count--;
			}
		}
		if(srcobjList->prev == NULL){
			cmsXml_FreeObjList(&srcobjList);
			break;
		}
		srcobjList = srcobjList->prev;
	}

	sobject = cmsXml_GetObjectByOID(srcrdmCB, OID, IAValue, NULL_IF_NOT_EXISTED);
	if(sobject != NULL){
		dobject = cmsXml_GetObjectByOID(dstrdmCB, OID, IAValue, ADD_IF_NOT_EXISTED);
		src = srcrdmCB->objectNode;
		dst = dstrdmCB->objectNode;
		if (flag == RESET_INDEXCHILD_OBJECT_VALUE){
			if ((dst->attributes & ATTR_ALWAYSACTIVE) != ATTR_ALWAYSACTIVE){
				dst->attributes &= ~ATTR_NODECONFIGURED;
			}
		}
		else if (flag == COPY_OBJECT_VALUE){
			dst->attributes = src->attributes;
		}

		if (dst->object_size == 0){
			return 0;
		}
		//sobject = cmsXmlGetObjRealAddr(srcrdmCB, NTOHDL(src->object));
		//dobject = cmsXmlGetObjRealAddr(dstrdmCB, NTOHDL(dst->object));
		meta_count = NTOHS(src->meta_count);
		//memcpy(object, sobject, node->object_size);

		memcpy(dobject, sobject, NTOHL(src->config_size));
		metaAddr = sobject -sizeof(cmsoffset_t);
		metaOffset = *((cmsoffset_t *)metaAddr);
		meta_ptr = cmsXmlGetObjRealAddr(srcrdmCB, NTOHDL(metaOffset));
		while(meta_count)
		{
			meta_len = *((uint8_t *)meta_ptr);
			if (meta_len != PADDING_META_LEN){
				type_size = NTOHL(*((uint32_t *)(meta_ptr + meta_len - sizeof(uint32_t))));
				paraOffset = NTOHDL(*((cmsoffset_t *)(meta_ptr + meta_len - (sizeof(cmsoffset_t)*2+sizeof(uint32_t)))));
				attrOffset = NTOHDL(*((cmsoffset_t *)(meta_ptr + meta_len - (sizeof(cmsoffset_t)*1+sizeof(uint32_t)))));
				attr = NTOHL(*((uint32_t *)(sobject+attrOffset)));
				if ((attr & PARAMETER_ATTR_CONFIG) != PARAMETER_ATTR_CONFIG) //Ex:interface name don't want user to modify, so its' value will be non-configure and read-only
				{
					if ((attr & PARAMETER_ATTR_READONLY) != PARAMETER_ATTR_READONLY){
						size = (int)(type_size & ~((uint32_t)PARAMETER_TYPE_CLASS_BITS));
						memcpy((dobject+paraOffset), (sobject+paraOffset), size);
					}
				}
			}
			meta_ptr = meta_ptr + meta_len;
			meta_count--;
		}
	}
	return 0;
}

#endif   //#ifndef SYSDEF_PARSER_ON_HOST

